/* *****************************************************************************
 * JFab (http://code.google.com/p/jfab)
 * Copyright (c) 2011 JFab.org
 * Admin jfab@jeffreythompson.net
 *
 * See the file "LICENSE.txt" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * *****************************************************************************/


package org.jfab.core.util;

import java.util.Map;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;


/**
 * Defines methods required by a compiler.
 *
 * @param  <T>  Type.
 */
public interface Compiler<T>
{
    /**
     * Compile multiple Java source strings and return a Map containing the
     * resulting classes.
     *
     * <p>Thread safety: this method is thread safe if the <code>classes</code>
     * and <code>diagnostics</code> are isolated to this thread.
     *
     * @param   classes      A Map whose keys are qualified class names and
     *                       whose values are the Java source strings containing
     *                       the definition of the class. A map value may be
     *                       null, indicating that compiled class is expected,
     *                       although no source exists for it (it may be a
     *                       non-public class contained in one of the other
     *                       strings.)
     * @param   diagnostics  Any diagnostics generated by compiling the source
     *                       are added to this list.
     *
     * @return  A mapping of qualified class names to their corresponding
     *          classes. The map has the same keys as the input <code>
     *          classes</code>; the values are the corresponding Class objects.
     *
     * @throws  JavaStringCompilerException  if the source cannot be compiled
     */
    Map<String, Class<T>> compile(final Map<String, CharSequence> classes,
        final DiagnosticCollector<JavaFileObject> diagnostics)
        throws JavaStringCompilerException;

    /**
     * Compile Java source in <code>javaSource</name> and return the resulting
     * class.
     *
     * <p>Thread safety: this method is thread safe if the <code>
     * javaSource</code> and <code>diagnostics</code> are isolated to this
     * thread.
     *
     * @param   qualifiedClassName  The fully qualified class name.
     * @param   javaSource          Complete java source, including a package
     *                              statement and a class, interface, or
     *                              annotation declaration.
     * @param   diagnostics         Any diagnostics generated by compiling the
     *                              source are added to this collector.
     * @param   types               zero or more Class objects representing
     *                              classes or interfaces that the resulting
     *                              class must be assignable (castable) to.
     *
     * @return  a Class which is generated by compiling the source
     *
     * @throws  JavaStringCompilerException  if the source cannot be compiled -
     *                                       for example, if it contains syntax
     *                                       or semantic errors or if dependent
     *                                       classes cannot be found.
     * @throws  ClassCastException           if the generated class is not
     *                                       assignable to all the optional
     *                                       <code>types</code>.
     */
    Class<T> compile(final String qualifiedClassName,
        final CharSequence javaSource,
        final DiagnosticCollector<JavaFileObject> diagnostics,
        final Class<?>... types) throws JavaStringCompilerException,
        ClassCastException;

    /**
     * @return  This compiler's class loader.
     */
    ClassLoader getClassLoader();

    /**
     * Load a class that was generated by this instance or accessible from its
     * parent class loader. Use this method if you need access to additional
     * classes compiled by {@link #compile(String, CharSequence,
     * DiagnosticCollector, Class...) compile()}, for example if the primary
     * class contained nested classes or additional non-public classes.
     *
     * @param   qualifiedClassName  the name of the compiled class you wish to
     *                              load
     *
     * @return  a Class instance named by <code>qualifiedClassName</code>
     *
     * @throws  ClassNotFoundException  if no such class is found.
     */
    Class<T> loadClass(final String qualifiedClassName)
        throws ClassNotFoundException;
}
